import { GraphNodeType } from "@/constants/Enums";
import { getUniqueName } from "@/util/common";
import { SysMLUtilHelper, MofModelRepositoryHelper } from 'src/api/sysml-imports';

export class GraphNodeUtil {
  /**
   * 判断parentNode是不是childNode祖先元素
   * @param parentNode
   * @param childNode
   */
  static isAncestorGraphNode(parentNode: GraphNode, childNode: GraphNode) {
    let curParent = childNode.container;
    while (curParent) {
      if (parentNode.id === curParent.id) {
        console.log(parentNode, curParent);
        return true;
      }
      curParent = curParent.container;
    }
    return false;
  }

  /**
   * 树上拖拽元素时判断childNode能否作为parentNode的子元素
   * @param childNode
   * @param parentNode
   * @param checkHasbeenChild 是否需要检查已经是子元素，图形拖动时用到
   */
  static isValidChildNode(childNode: GraphNode, parentNode: GraphNode, checkHasbeenChild = true) {
    //// 1. //// 自己不能容纳自己
    if (childNode === parentNode) return false;

    //// 2. 已经是父元素无需再更新
    if (checkHasbeenChild && childNode.container === parentNode) return false; ////

    //// 3. 子元素不能容纳父元
    if (this.isAncestorGraphNode(childNode, parentNode)) {
      console.log("子元素不能容纳父元");

      return false; //// 子元素不能容纳父元素
    }

    //// 4. 子元素名称重复不能拖入
    const existSameNameNode =  this.hasSameNameChild(parentNode, childNode);
    if (existSameNameNode) {
      console.log("子元素名称重复");
      return false;
    }

    const parentType = parentNode.getTypeName();
    const childType = childNode.getTypeName();

    //// 5. 无typeNameConfig配置不允许拖入
    const childTypeNameConfig = app.activeProject.configManager.getTypeNameConfigItem(childType);
    if (!childTypeNameConfig) return false;
    const parentTypeNameConfigItem = app.activeProject.configManager.getTypeNameConfigItem(
      parentType
    );
    if (!parentTypeNameConfigItem) return false;

    //// 5. edge不允许拖拽，也不允许作为拖拽的目标
    if (
      childTypeNameConfig.type === GraphNodeType.EDGE ||
      parentTypeNameConfigItem.type === GraphNodeType.EDGE
    ){
      console.log('edge 不能直接更改所在目录');
      return false;
    }

    //// 6. nestConfig没配置则不允许拖入（包含了不能向图中拖入子元素，不能向关系组节点拖拽子元素）
    const nestConfig = app.activeProject.configManager.getNestConfig()[parentType]; //// 符合nestConfig规则
    if (!nestConfig) return false;
    const exist = nestConfig.find(item => item.typeName === childType);
    if (!exist) {
      console.log('nestConfig 不允许包含');
      return false;
    }

    //// 7. 禁用的元素不能拖拽或作为拖拽的目标
    return !(childNode.disabled || parentNode.disabled);

    ////   parentType;
  }

  static isInstanceOf(type: string, parentType: string):boolean {
    if (app.activeProject){
      return app.activeProject.configManager && app.activeProject.configManager.getExtendsConfig()[type]?.has(parentType);
    }
  }
  static typeNameToStNameMap = {
    AllocateActivityPartitionVertical: 'AllocateActivityPartition',
    AllocateActivityPartitionHorizontal: "AllocateActivityPartition"
  }

  static is(type: string, parentType: string|string[], mode:'or'|'and' = 'or'):boolean{
    if (this.typeNameToStNameMap[type]){
      type = this.typeNameToStNameMap[type];
    }
    if (typeof parentType === 'string'){
      return this.isOrIsInstanceOf(type, parentType);
    } else {
      let extendsConfigItem = app.activeProject && app.activeProject.configManager && app.activeProject.configManager.getExtendsConfig()[type];
      if (!extendsConfigItem) return false;
      if (mode === 'or'){
        for (let i = 0; i < parentType.length; i++){
          if (type === parentType[i] || extendsConfigItem.has(parentType[i])){
            return true;
          }
        }
        return false;

      } else if (mode === 'and'){
        for (let i = 0; i < parentType.length; i++){
          if (!(type === parentType[i] || extendsConfigItem.has(parentType[i]))){
            return false;
          }
        }
        return true;
      }

    }

  }
  static isOrIsInstanceOf(type: string, parentType: string):boolean {
    if (app.activeProject){
      return type === parentType || (app.activeProject.configManager && app.activeProject.configManager.getExtendsConfig()[type]?.has(parentType));
    }
  }

  /**
   * 在popmenu上创建port时，计算port的x，y坐标
   * @param parentShape port的父图形
   */
  static getPopmenuPortPosition(parentShape: UmlShape): Point {
    const childShapes = parentShape.children;
    const existRightPorts = childShapes
      .filter(shape => {
        //// const typeName = shape.getTypeName();
        //// const typeNameConfigItem = app.activeProject.configManager.getTypeNameConfigItem(
        ////   typeName
        //// );
        //// if (
        ////   !typeNameConfigItem ||
        ////   typeNameConfigItem.type !== GraphNodeType.PORT
        //// )
        ////   return false;
        return shape.box.position === 'port' && shape.box.portDirection === "right";

      })
      .sort((i, j) => i.bounds.y - j.bounds.y);
    if (
      existRightPorts.length == 0 ||
      (existRightPorts[0] && existRightPorts[0].bounds.y > 16 + 30)
    ) {
      return { x: parentShape.bounds.width - 1, y: 10 };
    }
    let y = 10;
    for (let i = 0; i < existRightPorts.length; i++) {
      const p1 = existRightPorts[i];
      const p2 = existRightPorts[i + 1];
      if (!p2) {
        y = p1.bounds.y + p1.bounds.height + 10;
        break;
      } else if (p2.bounds.y - p1.bounds.y - p1.bounds.height > 16 + 20) {
        y = p1.bounds.y + p1.bounds.height + 10;
        break;
      }
    }
    return { x: parentShape.bounds.width - 1, y };
  }
  /**
   * 获得graphNode下的子元素的新名称
   * @param graphNode 父元素GraphNode
   * @param baseName 初始名称
   */
  static getNewChildNodeName(graphNode: GraphNode, baseName: string) {
    const nameList = graphNode.children.map(child => child.title);
    return getUniqueName(nameList, baseName);
  }
  /**
   * 是否有相同名称的子元素
   */
  static hasSameNameChild(graphNode: GraphNode, childNode: GraphNode) {
    return !!graphNode.children.find(i => i !== childNode &&  i.title === childNode.title);
  }
  static initProperty(graphNode:GraphNode){
    if (graphNode.getPropertyInit()){
      return;
    }
    const modelPropertyConfigItem = app.activeProject.configManager.getModelPropertyConfig()[graphNode.getTypeName()];
    const properties = modelPropertyConfigItem["properties"];
    const propertypeKeys = [];
    properties.forEach((property) => {
      propertypeKeys.push(property["key"]);
    });
    //// 聚合泛化的属性(即现有属性可以分离到实际类定义上)
    const typeNames = SysMLUtilHelper.generalTypeNames(graphNode);
    typeNames.forEach((typeName) => {
      const parentModelPropertyConfigItem = app.activeProject.configManager.getModelPropertyConfig()[typeName];
      if (parentModelPropertyConfigItem != undefined){
        const classType = parentModelPropertyConfigItem["fullName"];
        const classTypeArray = classType.split("::");
        if (classTypeArray.length > 0 ){
          const end = classTypeArray[classTypeArray.length - 1];
          if (end == typeName){
            const parentProperties = parentModelPropertyConfigItem["properties"];
            if (parentProperties){
              parentProperties.forEach( (parentProperty) =>
              {
                if (propertypeKeys.indexOf(parentProperty["key"]) < 0){
                  properties.push(parentProperty);
                  propertypeKeys.push(parentProperty["key"]);
                }
              }
              );
            }
          }
        }
      }
    });
    if (modelPropertyConfigItem){
      modelPropertyConfigItem["properties"] = properties;
      SysMLUtilHelper.initGraphElementProperty(graphNode, modelPropertyConfigItem);
    }
  }
  static isNodeDisabled(graphNode:GraphNode, project:Project){
    return graphNode.disabled || project.onlineConfig.packageStatus.get(graphNode.id) > 1;
  }

  static deleteProject(projectId:string){
    app.proxy.projects.delete(projectId);
    MofModelRepositoryHelper.removePool(projectId);

  }

}
